/*
 * Created on 2004-9-29
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package funccode;

/**
 * @author Administrator
 * 
 *         TODO To change the template for this generated type comment go to
 *         Window - Preferences - Java - Code Style - Code Templates
 */
public class RegTblGenerator {
	private StringBuffer frame;
	private static final int WORDLEN = 4;
	private static final int BYTELEN = 2;

	public RegTblGenerator() {
		super();
		frame = new StringBuffer();
	}

	private void checkUnsignedByte(int val) throws RegTblGeneratorException {
		if (val < 0 || val > 255)
			throw new RegTblGeneratorException("value " + val
					+ " out of unsigned byte range");
	}

	private void checkSignedByte(int val) throws RegTblGeneratorException {
		if (val < -128 || val > 127)
			throw new RegTblGeneratorException("value " + val
					+ " out of signed byte range");
	}

	private void checkUnsignedWord(int val) throws RegTblGeneratorException {
		if (val < 0 || val > 65535)
			throw new RegTblGeneratorException("value " + val
					+ " out of unsigned word range");
	}

	private void checkSignedWord(int val) throws RegTblGeneratorException {
		if (val < -32768 || val > 32767)
			throw new RegTblGeneratorException("value " + val
					+ " out of signed word range");
	}

	/**
	 * 
	 * @param start
	 *            StringBuffer��ʼλ��
	 * @param s
	 *            ���õ��ַ�
	 */
	private void setValue(int start, String s) {
		int ensureLen = start + s.length();
		int difLen = ensureLen - frame.length();
		for (int i = 0; i < difLen; i++)
			frame.append('0');
		frame.replace(start, ensureLen, s);
	}

	/**
	 * 
	 * @param val
	 *            ֵ
	 * @param len
	 *            ���ó���
	 * @return
	 */
	private String valueToString(int val, int len) {
		StringBuffer s = new StringBuffer(Integer.toHexString(val));
		int difLen = len - s.length();
		for (int i = 0; i < difLen; i++)
			s.insert(0, '0');
		return s.substring(s.length() - len).toUpperCase();
	}

	public void setUnsignedByte(int val, int offset, boolean isHigh)
			throws RegTblGeneratorException {
		this.checkUnsignedByte(val);
		if (isHigh)
			setValue(offset * WORDLEN, valueToString(val, BYTELEN));
		else
			setValue(offset * WORDLEN + BYTELEN, valueToString(val, BYTELEN));
	}

	public void setSignedByte(int val, int offset, boolean isHigh)
			throws RegTblGeneratorException {
		this.checkSignedByte(val);
		if (isHigh)
			setValue(offset * WORDLEN, valueToString(val, BYTELEN));
		else
			setValue(offset * WORDLEN + BYTELEN, valueToString(val, BYTELEN));
	}

	private static final char[] charArray = { '0', '1', '2', '3', '4', '5',
			'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

	public static char intToChar(int i) throws RegTblGeneratorException {
		if (i < 0 || i > charArray.length)
			throw new RegTblGeneratorException("can't cover int " + i
					+ " to valid char");
		return charArray[i];
	}

	public static char getHighNibble(byte b) throws RegTblGeneratorException {
		int n = b;
		return intToChar((n >> 4) & 0x0F);
	}

	public static char getLowNibble(byte b) throws RegTblGeneratorException {
		int n = b;
		return intToChar(n & 0x0F);
	}

	/**
	 * ����������Ѿ�ת����16����ascii�ַ�
	 * 
	 * @param val
	 *            ���õ�String��Ϊ����
	 * @param offset
	 *            ��ʼд�ĵ�ַ���Ĵ�����
	 * @param len
	 *            �ܹ�д�ĳ��ȣ����㣬��0
	 * @throws RegTblGeneratorException
	 */
	public void setText(String val, int offset, int len)
			throws RegTblGeneratorException {
		byte[] b = val.getBytes();
		if (b.length * 2 > len * WORDLEN)
			throw new RegTblGeneratorException("can't write string " + val
					+ " to regtable, it's too long");
		char[] buf = new char[len * WORDLEN];
		for (int i = 0; i < b.length; i++) {
			buf[i * BYTELEN] = getHighNibble(b[i]);
			buf[i * BYTELEN + 1] = getLowNibble(b[i]);
		}
		for (int i = (b.length) * BYTELEN; i < buf.length; i++)
			buf[i] = '0';
		String s = new String(buf);
		setValue(offset * WORDLEN, s);

	}

	public void setUnsignedWord(int val, int offset)
			throws RegTblGeneratorException {
		this.checkUnsignedWord(val);
		setValue(offset * WORDLEN, valueToString(val, WORDLEN));
	}

	public void setSignedWord(int val, int offset)
			throws RegTblGeneratorException {
		this.checkSignedWord(val);
		setValue(offset * WORDLEN, valueToString(val, WORDLEN));
	}

	private void ensureWordLen() {
		int mod = frame.length() % WORDLEN;
		for (int i = 0; i < mod; i++)
			frame.append('0');
	}

	// assert word placement
	public void appendUnsignedWord(int val) throws RegTblGeneratorException {
		this.checkUnsignedWord(val);
		this.ensureWordLen();
		this.frame.append(valueToString(val, WORDLEN));
	}

	// assert word placement
	public void appendSignedWord(int val) throws RegTblGeneratorException {
		this.checkSignedWord(val);
		this.ensureWordLen();
		this.frame.append(valueToString(val, WORDLEN));
	}

	public void appendUnsignedByte(int val) throws RegTblGeneratorException {
		this.checkUnsignedByte(val);
		this.frame.append(valueToString(val, BYTELEN));
	}

	public void appendSignedByte(int val) throws RegTblGeneratorException {
		this.checkSignedByte(val);
		this.frame.append(valueToString(val, BYTELEN));
	}

	// assert word placement
	public void appendRegTbl(RegTblGenerator val) {
		this.ensureWordLen();
		this.frame.append(val.toString());
	}

	public void setRegTbl(RegTblGenerator val, int offset) {
		setValue(offset * WORDLEN, val.toString());
	}

	public String toString() {
		return this.frame.toString();
	}
}
